class Compiler {
  constructor (vm) {
    this.el = vm.$el
    this.vm = vm
    // 立即编译模板
    this.compile(this.el)
  }
  // 编译模板，处理文本节点和元素节点
  compile (el) {
    let childNodes = el.childNodes
    // childNodes 是一个伪数组 转换成数组 Array.from(childNodes)
    Array.from(childNodes).forEach(node => {
      // 处理文本节点
      if (this.isTextNode(node)) {
        this.compileText(node)
      }else if(this.isElementNode(node)){
        // 处理元素节点
        this.compileElement(node)
      }

      // 判断node节点，是否有子节点，如果有子节点，要递归调用compile
      if(node.childNodes && node.childNodes.length) {
        this.compile(node)
      }
    })
  }
  // 编译元素节点，处理指令
  compileElement (node) {
    // 遍历所有的属性节点
    Array.from(node.attributes).forEach(attr => {
      // 判断是否是指令
      let attrName = attr.name 
      if(this.isDirective(attrName)){
        // v-text --> text
        attrName = attrName.substr(2)
        let key = attr.value
        //判断是否是v-on指定  
        if(attrName.startsWith('on')){
          //获取事件类型
          let eventType = attrName.replace('on:','')
          return this.onUpdate(node,key,eventType)
        }
        this.update(node,key,attrName)
      }
    })
  }
  onUpdate(node,key,event){
    this.eventUpdater(node,key,event)
  }
  update (node,key,attrName){
    let updateFn = this[attrName+'Updater']
    // 此处的this 指 compiler对象
    updateFn && updateFn.call(this,node,this.vm[key],key)
  }
  // 处理 v-text 指令
  textUpdater(node,value,key){
    node.textContent = value
    // 创建watcher对象，数据改变更新视图
    new Watcher(this.vm,key,(newValue)=>{
      node.textContent = newValue
    })
  }
  // v-model
  modelUpdater (node ,value,key){
    node.value = value
    // 创建watcher对象，数据改变更新视图
    new Watcher(this.vm,key,(newValue)=>{
      node.value = newValue
    })
    // 双向绑定
    node.addEventListener('input',() => {
      this.vm[key] = node.value
    })
  }
  htmlUpdater (node, value, key) {
    node.innerHTML = value
    // 创建watcher对象，数据改变更新视图
    new Watcher(this.vm,key,(newValue)=>{
      node.innerHTML = newValue
    })
  }
  eventUpdater (node, key, event){
    node.addEventListener(event,this.vm[key])
  }
  // 编译文本节点，处理差值表达式
  compileText (node) {
    // {{ msg}}
    let reg = /\{\{(.+?)\}\}/
    let value = node.textContent
    if(reg.test(value)){
      let key = RegExp.$1.trim()
      node.textContent = value.replace(reg,this.vm[key])

      // 创建watcher对象，数据改变更新视图
      new Watcher(this.vm,key,(newValue) => {
        node.textContent = newValue
      })
    }
  }
  // 判断元素属性是否是指令
  isDirective (attrName) {
    return attrName.startsWith('v-')
  }
  // 判断节点是否是文本节点
  isTextNode (node) {
    return node.nodeType === 3
  }
  // 判断节点是否是元素节点
  isElementNode (node) {
    return node.nodeType === 1
  }
}